package games.tictactoe;

import games.Rules;
import games.Player;
import games.Board;
import games.Move;
import games.Location;
import java.util.ArrayList;

final class TicTacToeRules implements Rules
{
    private static TicTacToeRules mRules;
    private int[] mWinningStroke = null; /* TODO: should not be a member of this object */
    
    private TicTacToeRules()
    {
    }
    
    static TicTacToeRules getInstance()
    {
        if (mRules == null)
            mRules = new TicTacToeRules();
        return mRules;
    }
    
    public boolean isMoveLegal(Move move)
    {
    	// TODO: remove the double calls for getLocation/Board.
        if (move.getPlayer() == null || move.getBoard() == null || move.getLocation() == null)
            return false;
        
        Location location = move.getLocation();
        Board board = (TicTacToeBoard)(move.getBoard());
        return !board.isLocationOccupied(location);
    }
    
    public Player getNextPlayer(ArrayList<Player> players, Player currentPlayer)
    {
        return (currentPlayer.getType() == TicTacToePlayerType.X) ? (TicTacToeAIPlayer)players.get(1) : (TicTacToePlayer)players.get(0);
    }
    
    public ArrayList<Player> createGamePlayers()
    {
        // Player index 0 is always 'X'.
        // Player index 1 is always 'O'.
        ArrayList<Player> players = new ArrayList<Player>(2);
        Player player = new TicTacToePlayer().setType(TicTacToePlayerType.X);
        players.add(player);
        player = new TicTacToeAIPlayer().setType(TicTacToePlayerType.O);
        players.add(player);
        return players;
    }
    
    public boolean isGameDraw(Board board)
    {
        if (!isGameWin(board))
        {
            for (int i = 1 ; i <= 9 ; ++i)
            {
                Location location = (new TicTacToeLocation()).setLocation(i);
                if (board.getPieceByLocation(location) == null )
                {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
    
    public boolean isGameWin(Board board)
    {
        return isBoardLineComplete(board, 1,2,3)
                || isBoardLineComplete(board, 4,5,6)
                || isBoardLineComplete(board, 7,8,9)
                || isBoardLineComplete(board, 1,4,7)
                || isBoardLineComplete(board, 2,5,8)
                || isBoardLineComplete(board, 3,6,9)
                || isBoardLineComplete(board, 1,5,9)
                || isBoardLineComplete(board, 3,5,7);
    }
    
    public int[] getWinningStroke()
    {
        return mWinningStroke; /* TODO: should not be a member of this object */
    }
    
    private boolean isBoardLineComplete(Board board, int location1, int location2, int location3)
    {
    	/* 
    	 * TODO: remove the duplicate allocations.
    	 */
    	
        if ((board.getPieceByLocation(new TicTacToeLocation(location1)) != null)
                && (board.getPieceByLocation(new TicTacToeLocation(location2)) != null)
                && (board.getPieceByLocation(new TicTacToeLocation(location3)) != null))
        {
            if (board.getPieceByLocation(new TicTacToeLocation(location1)).getType().equals(
                    board.getPieceByLocation(new TicTacToeLocation(location2)).getType())
                && board.getPieceByLocation(new TicTacToeLocation(location1)).getType().equals(
                        board.getPieceByLocation(new TicTacToeLocation(location3)).getType()))
            {
                mWinningStroke = new int[3]; /* TODO: should not be a member of this object */
                mWinningStroke[0] = location1;
                mWinningStroke[1] = location2;
                mWinningStroke[2] = location3;
                return true;
            }
        }
        
        return false;
    }
}
